//
// RS Game Framework
// Copyright © 2009 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//

#ifndef RS_REFERENCECOUNTED_HPP
#define RS_REFERENCECOUNTED_HPP

#include "rs/Assert.hpp"
#include "rs/Atomic.hpp"

namespace rs
{
    class ReferenceCounted
    {
    public:
                
        virtual ~ReferenceCounted();
        
        Int32 GetReferenceCount() const;        
        
        void IncrementReference() const;
        
        void DecrementReference() const;
        
    protected:
        
        explicit ReferenceCounted(Int32 referenceCount = 0);
                        
    private:
        
        mutable Int32 volatile referenceCount_;
    };
    
    
    
    inline ReferenceCounted::ReferenceCounted(Int32 referenceCount)
    : referenceCount_(referenceCount) {
    }
    
    inline ReferenceCounted::~ReferenceCounted() {
        RS_ASSERT(atomic::AddFetch(&referenceCount_, -1) < 0, "Cannot delete an object with references");
    }
    
    inline Int32 ReferenceCounted::GetReferenceCount() const {
        return referenceCount_;
    }        
    
    inline void ReferenceCounted::IncrementReference() const {
        Int32 newValue = atomic::AddFetch(&referenceCount_, 1);
        RS_ASSERT(newValue > 0, "Cannot retain a deleted object");
    }
    
    inline void ReferenceCounted::DecrementReference() const {
        Int32 newValue = atomic::AddFetch(&referenceCount_, -1);
        RS_ASSERT(newValue >= 0, "Cannot retain a deleted object");
        if (newValue == 0) {
            delete this;
        }
    }
}

#endif // RS_REFERENCECOUNTED_HPP